<html>
<script>
  var pages = [
    "bugzilla.mozilla.org/",
    "lxr.mozilla.org/",
    "vanilla-page/"
  ];
  var pages_i18n = [];

  var NUM_PAGES;
  var NUM_CYCLES;

  function parseParams() {
    var s = document.location.search.substring(1);
    var params = s.split('&');
    for (var i = 0; i < params.length; ++i) {
      var fields = params[i].split('=');
      switch (fields[0]) {
      case 'cycles':
        NUM_CYCLES = (fields[1] - 0);
        break;
      case 'pages':
        NUM_PAGES = (fields[1] - 0);
        break;
      case 'i18n':
        if (fields[1] == '1') {
          pages = pages.concat(pages_i18n);
        }
        break;
      }
    }
    if (!NUM_PAGES)
      NUM_PAGES = pages.length;
    if (!NUM_CYCLES)
      NUM_CYCLES = 5;
  }
  parseParams();

  var timeVals = new Array(NUM_PAGES);  // matrix of times
  for (var i = 0; i < timeVals.length; ++i) {
    timeVals[i] = new Array;
  }
  var tstart;
  var index = 0;
  var cycle = 0;

  // returns an object with the following properties:
  //   min  : min value of array elements
  //   max  : max value of array elements
  //   mean : mean value of array elements
  //   vari : variance computation
  //   stdd : standard deviation, sqrt(vari)
  //   indexOfMax : index of max element (the element that is
  //                removed from the mean computation)
  function getArrayStats(ary) {
    var r = {};
    r.min = ary[0];
    r.max = ary[0];
    r.indexOfMax = 0;
    var sum = 0;
    for (var i = 0; i < ary.length; ++i) {
      if (ary[i] < r.min) {
        r.min = ary[i];
      } else if (ary[i] > r.max) {
        r.max = ary[i];
        r.indexOfMax = i;
      }
      sum = sum + ary[i];
    }

    // median
    sorted_ary = ary.concat();
    sorted_ary.sort();
    // remove longest run
    sorted_ary.pop();
    if (sorted_ary.length%2) {
      r.median = sorted_ary[(sorted_ary.length-1)/2]; 
    }else{
      var n = Math.floor(sorted_ary.length / 2);
      r.median = (sorted_ary[n] + sorted_ary[n + 1]) / 2;
    }

    // ignore max value when computing mean and stddev
    r.mean = (sum - r.max) / (ary.length - 1);

    r.vari = 0;
    for (var i = 0; i < ary.length; ++i) {
      if (i == r.indexOfMax)
        continue;
      var d = r.mean - ary[i];
      r.vari = r.vari + d * d;
    }

    r.vari = r.vari / (ary.length - 1);
    r.stdd = Math.sqrt(r.vari);
    return r;
  }

  function appendTableCol(tr, text) {
    var doc = tr.ownerDocument;
    var td = doc.createElement("TD");
    td.appendChild(doc.createTextNode(text));
    tr.appendChild(td);
    return td;
  }

  function dumpReport() {
    var all = new Array();
    var counter = 0;
    
    for (var i = 0; i < timeVals.length; ++i) {
      for (var j = 0; j < timeVals[i].length; ++j) {
        all[counter] = timeVals[i][j];
        ++counter;
      }
    }

    // avg and avg median are cumulative for all the pages
    var avgs = new Array();
    var medians = new Array();
    for (var i = 0; i < timeVals.length; ++i) {
       avgs[i] = getArrayStats(timeVals[i]).mean;
       medians[i] = getArrayStats(timeVals[i]).median;
    }
    var avg = getArrayStats(avgs).mean;
    var avgmed = getArrayStats(medians).mean;

    var r = getArrayStats(all);
    dump(
      "(tinderbox dropping follows)\n"+
      "_x_x_mozilla_page_load,"+avgmed+","+r.max+","+r.min+"\n"+
      "_x_x_mozilla_page_load_details,avgmedian|"+avgmed+"|average|"+avg.toFixed(2)+"|minimum|"+r.min+"|maximum|"+r.max+"|stddev|"+r.stdd.toFixed(2)+":"
    );

    for (var i = 0; i < timeVals.length; ++i) {
      r = getArrayStats(timeVals[i]);
      dump(
        '|'+
        i+';'+
        pages[i]+';'+
        r.median+';'+
        r.mean+';'+
        r.min+';'+
        r.max
      );
      for (var j = 0; j < timeVals[i].length; ++j) {
        dump(
          ';'+timeVals[i][j]
        );
      }
    } 
  }

  function showReport() {
    var doc = frames["content"].document;
    var tbody = doc.getElementById("tbody");
    for (var i = 0; i < timeVals.length; ++i) {
      var tr = doc.createElement("TR");

      appendTableCol(tr, pages[i]);

      var r = getArrayStats(timeVals[i]);
      appendTableCol(tr, r.min.toFixed(2));
      appendTableCol(tr, r.max.toFixed(2));
      appendTableCol(tr, r.mean.toFixed(2));
      appendTableCol(tr, r.stdd.toFixed(2));
      appendTableCol(tr, r.median.toFixed(2));

      for (var j = 0; j < timeVals[i].length; ++j) {
        var tv = timeVals[i][j];
        var td = appendTableCol(tr, tv);
        if (j == r.indexOfMax)
          td.setAttribute("class", "discarded");
      }

      tbody.appendChild(tr);
    }
  }

  function loadPage(i) {
    tstart = new Date();
    frames["content"].document.location = "base/" + pages[i] + "index.html";
  }

  function frameLoad() {
    if (cycle == NUM_CYCLES) {
      showReport();
      dumpReport();
      window.close();
      return;
    }

    var tend = new Date();
    var href = frames["content"].document.location.href;
    if (href == "about:blank")
      return;
    var tdelta = tend - tstart;
    timeVals[index].push(tdelta);
    var fields = href.split('/');

    var text = (cycle + 1) + ', ' + (index + 1) + ', ' + fields[fields.length - 2] + ", " + tdelta;

    var doc = frames["header"].document;
    var body = doc.body;
    while (body.firstChild)
      body.removeChild(body.firstChild);
    body.appendChild(doc.createTextNode(text));

    if (++index == NUM_PAGES) {
      index = 0;
      if (++cycle == NUM_CYCLES) {
        // display summary
        frames["content"].document.location = "report.html";
        return;
      }
    }

    window.setTimeout("loadPage(" + index + ")", 500);
  }

  function init() {
    window.resizeTo(800, 800);
    window.setTimeout("loadPage(" + index + ")", 500);
  }
</script>
<frameset rows="40,*" onload="init()">
  <frame name="header" src="header.html">
  <frame name="content" src="" onload="frameLoad()">
</frameset>
</html>
